#include <QDebug>
#include <QGridLayout>
#include <QLabel>
#include <QTextEdit>
#include <QMouseEvent>
#include <QCloseEvent>

#include "matrixviewer.h"
#include "datacontroller.h"
#include "messagedisplay.h"
#include "scrollline.h"
#include "textspinbox.h"

MatrixViewer::MatrixViewer(QWidget *parent,
                           SystemControl *system/*,
                           QVector<Rule *> *rules*/):
        QWidget(parent),
        m_system(system)
{

    /* Set the title of this window
     */
    this->setWindowTitle("Output Matrix");

    /* Set the layout */
    m_layout = new QGridLayout(this);
    this->setLayout(m_layout);
}

void MatrixViewer::init() {

    /* Since this window has to be reinitialized every time it is opened, clear
     * whatever may have been on it before hand, and re-initialize it
     */
    this->clearAll();

    /* Get a DataController */
    DataController* system = DataController::instance();

    /* We have to get the number of unique inputs from set one, and the number
     * of unique inputs from set two so that we know the size of matrix that
     * must be generated to support the size of the sets entered
     */
    const QStringList& inputSetOne = system->getInputOneNames();
    const QStringList& inputSetTwo = system->getInputTwoNames();
    const QStringList& outputSet = system->getOutputNames();

    QList<OutputElem> outputIndices;

    /* Get the system's rule list */
    //const QVector<Rule *>& ruleList = DataController::instance()->getRuleList();

    /* Create lists of the unique inputs so that we know how to size the output
     * matrix
     */
//    int nRules = ruleList.size();
//
//    for ( int i = 0; i < nRules; ++i ) {
//
//		/* Get all of the required text elements for easy access */
//        const QString& firstInput = ruleList.at(i)->getFirstInput();
//        const QString& secondInput = ruleList.at(i)->getSecondInput();
//        const QString& output = ruleList.at(i)->getOutput();
//
//        /* Get the indices in the arrays for the first and second input values
//         * so that they can be added to the matrix in the correct order
//         */
//        int firstIndex = inputSetOne.indexOf(firstInput);
//        int secondIndex = inputSetTwo.indexOf(secondInput);
//
//        /* Add the output info to the array */
//        outputIndices.push_front(OutputElem(output, firstIndex, secondIndex));
//    }

    for (int i = 0; i < inputSetOne.size(); ++i)
    {
        for (int j = 0; j < inputSetTwo.size(); ++j)
        {
            const QString& output = DataController::instance()->findRule(inputSetOne.at(i),
                                                 inputSetTwo.at(j));
            outputIndices.push_front(OutputElem(output, i, j));

        }
    }
    /* Create the top row of labels */
    for ( int i = 0; i < inputSetOne.size(); ++i ) {
        m_a_labels.push_back(new QLabel(inputSetOne.at(i)));
        m_layout->addWidget(m_a_labels.at(i), 0, i+1);
    }

    /* Create the left row of labels */
    for ( int i = 0; i < inputSetTwo.size(); ++i ) {
        m_b_labels.push_back(new QLabel(inputSetTwo.at(i)));
        m_layout->addWidget(m_b_labels.at(i), i+1, 0);
    }

    /* Size the output matrix and add all the text editors to it. */
    m_outputs.resize(inputSetTwo.size());
    for ( int i = 0; i < inputSetTwo.size(); ++i ) {
        for ( int j = 0; j < inputSetOne.size(); ++j ) {
            m_outputs[i].push_back(new TextSpinBox());
            m_layout->addWidget(m_outputs.at(i).at(j), i+1, j+1 );
            connect(m_outputs.at(i).at(j), SIGNAL(textChanged()),
                    this, SLOT(updateRules()));
            //m_outputs.at(i).at(j)->
        }
    }

    QListIterator<OutputElem> iter(outputIndices);

    while(iter.hasNext())
    {
        const OutputElem& temp = iter.next();

        for (int i = 0; i < outputSet.size(); ++i)
        {
            if (temp.text == outputSet.at(i))
            {
                m_outputs[temp.vIndex][temp.hIndex]->setList(outputSet);
                m_outputs[temp.vIndex][temp.hIndex]->setText(outputSet.at(i));

                //m_outputs[temp.vIndex][temp.hIndex]->setList(outputSet);
            }
        }
	}
}

void MatrixViewer::clearAll() {

    while ( !m_a_labels.isEmpty() ) {
        delete m_a_labels.back();
        m_a_labels.pop_back();
    }

    while ( !m_b_labels.isEmpty() ) {
        delete m_b_labels.back();
        m_b_labels.pop_back();
    }

    for ( int i = 0; i < m_outputs.size(); ++i )
        while ( !m_outputs.at(i).isEmpty() ) {
            delete m_outputs[i].back();
            m_outputs[i].pop_back();
        }
}

void MatrixViewer::closeEvent(QCloseEvent *)
{
    /* Create a new array or rules that can be passed into the DataController
        to replace the old one.
     */
    QVector<Rule *> newRules;
    for( int i = 0; i < m_outputs.size(); ++i )
        for ( int j = 0; j < m_outputs[i].size(); ++j )
            if( m_outputs[i][j]->displayText() != "NO RULE")
                newRules.append(new Rule(m_a_labels[j]->text(),
                                         m_b_labels[i]->text(),
                                         m_outputs[i][j]->displayText()));

    DataController::instance()->setRuleList(newRules);
}

void MatrixViewer::updateRules()
{
    /* Create a new array or rules that can be passed into the DataController
        to replace the old one.
     */
    QVector<Rule *> newRules;
    for( int i = 0; i < m_outputs.size(); ++i )
        for ( int j = 0; j < m_outputs[i].size(); ++j )
            if( m_outputs[i][j]->displayText() != "NO RULE")
                newRules.append(new Rule(m_a_labels[j]->text(),
                                         m_b_labels[i]->text(),
                                         m_outputs[i][j]->displayText()));

    DataController::instance()->setRuleList(newRules);

}
